local skynet        = require "skynet"
local util          = require "util"
local constant      = require "constant"
local table_def     = require "table_def"
local string_format = string.format

local table_unpack  = table.unpack
local table_insert  = table.insert
local table_remove  = table.remove
local math_random   = math.random
local math_floor	= math.floor
local math_ceil     = math.ceil

local utils         = require "utils"
local util          = require "util"
local nn_rule       = require "niuniu.nn_rule"

local M = {}

local Methods = {}
local MT = {
    __index = Methods
}

-- math.random(1,1000)

function M.new(uid, player_info, addr, fd,game_type,kpqz_conf)
  --  print("new_robot=============",tostring_r(player_info))
 --   print_r(player_info)
    local o = {
        uid 					= uid,
        player_info 			= player_info,
        addr 					= addr,
        fd 						= fd,
        start_time 				= util.get_now_time(),
        time_to_bet 			= false,
        time_to_grab 			= false,
        time_to_cacl_cattle 	= false,
        bet_left_time 			= 0,
        grab_left_time 			= 0,        
        calc_cattle_left_time 	= 0,
        bet_count 				= 0,
        game_type               = game_type,
		
		life_duration			= math_random(10 * 60, 60 * 60), --机器人生命周期 10分钟~60分钟
        last_bet_time           = 0,
        leave                   = false,
        kpqz_conf               = kpqz_conf,
        record_last_player_bet  = 0,     --上一局真实玩家下注总额
        brnn_begin_bet_time     = false,        --百人牛牛开始下注的时间
        brnn_bet_time           = 7,     --百人牛牛机器人下注总时间(不能超过十秒)
        brnn_will_sit           = false,
        req_sit_time            = false,
        sit_position            = false,  --请求入座的位置
        coins_type              = coins_type,
        on_exiting              = false,
        total_bet               = 0,
        side_bet                = {},
        time_bet                = {},--时间区间下注额度,倒计时15~10秒为第一区间，倒计时10~5秒为第二区间，倒计时5~0秒为第三区间
    }

    return setmetatable(o, MT)
end

function Methods:on_register(uid)
    if uid ~= self.uid then
--        errlog(string_format("uid(%d) self.uid(%d) error", uid, self.uid))
        return false
    end

	local rob_info = {
		client_version 	= '',
		channel 		= '',
        cur_channel     = '',
		device_id 		= '',
		device_brand 	= '',
	}
    skynet.send(self.addr, "lua", "enter", self.uid, self.fd, rob_info)
end

--百人牛牛下注额度
function Methods:set_bet_coins(record_last_player_bet,robot_total_coins_type)
    local player_info = self.player_info
    if self.uid == self.instance:get_banker_uid() then --上庄机器人不投注
        return
    end

    local robot_total_coins = robot_total_coins_type[player_info.coins_type] or 0
    local robot_control = _ENV.global_configs.robot[player_info.type]
    local robot_cfg = robot_control.robot_type_list[player_info.coins_type]

    local instance = self.instance
    local vip_seat_rate = robot_cfg.vip_seat_rate
    if math_random(1,100) <= vip_seat_rate then
        --请求上座
        self.brnn_will_sit = true
        self.req_sit_time = util.get_now_time() + math_random(1,20)          --随机一个时间入座
        self.sit_position = math_random(1,6)
    end

    --确定各区域的下注上限额
    local bet_min           --机器人下注下限
    local last_bet_rate     --上局下注选用比例
    local bet_area_percent  --各下注区域比例

    --计算各个区域下注额度上限
    if instance.is_robot_banker then 
        bet_min = robot_cfg.system_bet_min
        bet_area_percent = utils.str_split(robot_cfg.system_bet_area,',')
        last_bet_rate = robot_cfg.system_last_bet_rate / 100
    else
        bet_min = robot_cfg.player_bet_min
        bet_area_percent = utils.str_split(robot_cfg.player_bet_area,',')
        last_bet_rate = robot_cfg.player_last_bet_rate / 100
    end

    --确定所有机器人下注总额=下注下限+上局玩家下注总量×下注选用比例
    local total_bet = bet_min + record_last_player_bet * last_bet_rate 
    --print("set_bet_coins===========111",total_bet,bet_min,record_last_player_bet,last_bet_rate)
    --算出单个机器人的下注额度=（单个机器人携带量/所有机器人的总携带×所有机器人下注总额
    local tmp_total_coins = (robot_total_coins == 0) and 1 or robot_total_coins
    local bet_coins = ((player_info.coins or 0)/tmp_total_coins) * total_bet
    --print("set_bet_coins===========222",uid,player_info.coins,tmp_total_coins,total_bet)
    --单个机器人实际下注额度=单个机器人下注额度×浮动值（80%~250%
    local bet_float = utils.str_split(robot_cfg['bet_area_float'],'-')
    local float = math_random(tonumber(bet_float[1]),tonumber(bet_float[2]))
    bet_coins = math_floor(bet_coins * (float / 100))

    --算出各区域下注概率
    local side_bet = {}     --各下注区域下注概率
    for side = 1, 4 do
        side_bet[side] = tonumber(bet_area_percent[side] or 0)
    end

    self.total_bet = bet_coins --个人下注总额
    self.side_bet = side_bet --个区域下注限制

    --第一区间有60%概率下注30%~70%的金币,第二区间有40%概率下20%~50%的金币
    for i=1,3 do
        self.time_bet[i] = 0
    end
    if math_random(1,100) < 60 then
        local rate = math_random(30,70)
        self.time_bet[1] = math_floor(bet_coins * rate / 100)
        bet_coins = bet_coins - self.time_bet[1]
    end
    if math_random(1,100) < 40 then
        local rate = math_random(20,50)
        self.time_bet[2] = math_floor(bet_coins * rate / 100)
        bet_coins = bet_coins - self.time_bet[2]
    end
    self.time_bet[3] = bet_coins

    --print("brnn_tmp_total_coins========33",self.uid,tostring_r(self.time_bet))
end

function Methods:on_start(instance,grab_banker_max_times,record_last_player_bet,robot_total_coins_type)
  --  print("grab_banker_max_times",grab_banker_max_times)

    self:reset()
    self.instance = instance
    self.grab_banker_max_times = grab_banker_max_times
end

function Methods:reset()
    self.instance 				= nil
    self.bet_count 				= 0 
    self.time_to_bet 			= false
    self.time_to_grab 			= false
    self.time_to_cacl_cattle 	= false

    self.bet_left_time 			= 0
    self.grab_left_time 		= 0
    self.calc_cattle_left_time 	= 0

	self.flottant				= 0.2 ----  -20%~20%
    self.leave = false
    
    self.record_last_player_bet = 0     --上一局真实玩家下注总额
    self.brnn_begin_bet_time    = false --百人牛牛开始下注的时间
    self.brnn_bet_time          = 7     --百人牛牛下注总时间
    self.brnn_will_sit          = false 
    self.req_sit_time           = false
    self.total_bet              = 0    --当局总下注额
    self.side_bet               = {}   --区域下注概率
    self.time_bet               = {}   --时间区域下注额
end

function Methods:kpqz_close_robot()
    local close = false
    local curr_time = util.get_now_time()

  --  print("kpqz_close_robot===========",self.uid,curr_time - self.start_time > self.life_duration)
    if curr_time - self.start_time > self.life_duration then
        close = true
    end

    return close
end

function Methods:close_robot()
    local instance = self.instance
    --print("instance.game_type===============",instance.game_type)
    return self:kpqz_close_robot()   
end

--机器人使用表情
function Methods:on_use_picture(uid,pic_conf,is_enter)
    if self.uid ~= uid then return end
    if not pic_conf then
        print(uid,"=====pic_conf is nil ===")
        return
    end

    local select_pic,delay_time
    if self.instance then
        select_pic,delay_time = self.instance:robot_can_use_pic(pic_conf)
    elseif is_enter then   --玩家刚进来时instance可能未初始化
        if math_random(1,100) <= pic_conf.use_rate then
            local use_pic = pic_conf.select_pic 
            select_pic = use_pic[math_random(1,#use_pic)]
            if pic_conf.delay_time and pic_conf.delay_time[1] and pic_conf.delay_time[2] then
                delay_time = math_random(pic_conf.delay_time[1],pic_conf.delay_time[2])
            end
        end 
    end
    if select_pic then
        if not delay_time or delay_time < 2 then 
            delay_time = math_random(2,6)     --至少给个2s种的延时吧
        end
        local msg = {
            type = 1,
            picture_id = select_pic,
        }
        if not self.picture_list then
            self.picture_list = {}
        end
        table_insert(self.picture_list,{
            send_time = util.get_now_time() + delay_time,    --每个动作之后，过两秒再发，避免动作和表情包同步，太假
            msg = msg
        }) 
        if self.instance then
            self.instance:add_use_pic_num()
        end
    end   
end

function Methods:judge_use_pic(curr_time)
    --上一次发表情的时间间隔小于1s，先不发，避免两个表情同步
    if self.last_pic_time and curr_time - self.last_pic_time < 1 then
        return
    end
    local picture_list = self.picture_list
    if picture_list then
        if #picture_list > 2 then
            table_remove(self.picture_list,1)
        end
        for k = #picture_list,1,-1 do
            local pic_info = picture_list[k]
            if curr_time > pic_info.send_time then
                skynet.send(self.addr,'lua','REQ_CHAT',self.uid,pic_info.msg,self.fd)
                table_remove(self.picture_list,k)
                return
            end
        end
    end
end

function Methods:on_game_over()
    if self:close_robot() then
        skynet.send(self.addr, "lua", "REQ_LEAVE", self.uid, {}, self.fd)
        self.on_exiting = true
    end

    --self.picture_list = nil
    self.last_pic_time = nil
end

function Methods:judge_sit()
    local curr_time = util.get_now_time()
    if self.brnn_will_sit and curr_time > self.req_sit_time and self.sit_position then
        self.brnn_will_sit = false
        return true
    end
    return false
end

function Methods:judge_banker()
    local curr_time = util.get_now_time()
    if self.do_banker_time and curr_time > self.do_banker_time then
        self.do_banker_time = nil
        return true
    end

    return false
end

local function rand_side(side_bet)
    local side = 1
    local sum = 0
    for k,v in pairs(side_bet) do
        sum = sum + v
    end

    local rand_num = math_random(1,sum)
    local tmp_sum = 0
    for side,v in pairs(side_bet) do
        tmp_sum = tmp_sum + v
        if rand_num <= tmp_sum then
            return side
        end
    end

    return side
end

function Methods:on_time_to_grab(grab_left_time)
--    dbglog(string_format("grab_left_time(%d)", grab_left_time))
    self.grab_left_time = util.get_now_time() + math_random(3,4)
    self.time_to_grab = true
end

function Methods:on_time_to_bet(bet_left_time,record_last_player_bet)
    --dbglog(string_format("bet_left_time(%d)", bet_left_time))
    self.bet_left_time = util.get_now_time() + math_random(3,5)
    self.last_bet_time = util.get_now_time() + math_random(2,3)
    self.time_to_bet = true
    self.record_last_player_bet = record_last_player_bet      --上一局玩家下注总额
    self.brnn_begin_bet_time = util.get_now_time() + math_random(2,2)  --百人牛牛开始下注的时间
    self.brnn_bet_time = bet_left_time + 3                    --百人牛牛机器人下注总时间(不能超过十秒)
end

function Methods:on_time_to_cacl_cattle(calc_cattle_left_time)
 --   dbglog(string_format("calc_cattle_left_time(%d)", calc_cattle_left_time))
    self.calc_cattle_left_time = calc_cattle_left_time
    self.time_to_cacl_cattle = true
end

local function get_first_four_cards(self)
    local side_cards_map = self.instance:get_side_cards_map()
    local player_data_map = self.instance:get_player_data_map()
    local side = player_data_map[self.uid].side
    local tmp_cards_list = side_cards_map[side]
    local self_card_list = {}

    for i = 1, 4 do 
        table_insert(self_card_list, tmp_cards_list[i])
    end

    return self_card_list
end

local function random_index(rob_prob_info)
    if not next(rob_prob_info) then
        return 0
    end

    local total = 0
    for _,value in pairs(rob_prob_info) do
        total = total + value
    end
    local rand = math_random(1,total)
    local curr = 0
    for index,value in ipairs(rob_prob_info) do
        curr = curr + value
        if rand <= curr then
            return index
        end
    end

    return 0
end

local function get_banker_times(self)
    local uid = self.uid
    local tile_list = get_first_four_cards(self)
    local card_value = nn_rule.get_cattle_four_number(tile_list)
    local kpqz_conf = self.kpqz_conf
    local rob_config = kpqz_conf.rob_config
    local banker_times = 0
    for _,rob_info in pairs(rob_config) do
        if card_value >= rob_info[1] and card_value <= rob_info[2] then
            local index = random_index(rob_info[3])
            banker_times = index - 1
            break
        end
    end

    return banker_times
end

local function get_bet_times(self)
    local uid = self.uid
    local tile_list = get_first_four_cards(self)
    local card_value = nn_rule.get_cattle_four_number(tile_list)
    local kpqz_conf = self.kpqz_conf
    local bet_config = kpqz_conf.bet_config
    local bet_times = 0
    for _,bet_info in pairs(bet_config) do
        if card_value >= bet_info[1] and card_value <= bet_info[2] then
            local index = random_index(bet_info[3])
            bet_times = index * 5
            break
        end
    end

    return bet_times
end

function Methods:kpqz_operate_logic()
    local instance = self.instance
    --self:judge_use_pic(util.get_now_time())

    if self.time_to_grab then
        local now_time = util.get_now_time()
        if instance and self.grab_left_time and now_time <= self.grab_left_time then --延迟1秒
            return
        end
        self.time_to_grab = false

        local grab_list = constant.KPQZ_NN_GRAB_BANKER_TIMES_LIST
        local size = #grab_list
        local banker_times = get_banker_times(self)
        if self.grab_banker_max_times and banker_times > self.grab_banker_max_times then
            banker_times = self.grab_banker_max_times
        end

        skynet.send(self.addr, "lua", "REQ_GRAB_BANKER", self.uid, { banker_times = banker_times }, self.fd)
    elseif self.time_to_bet and instance:is_betting() and self.uid ~= instance.banker_uid then
        if util.get_now_time() <= self.bet_left_time then
            return
        end

        self.time_to_bet = false
        local banker_info = instance:get_banker_info()
        local dizhu = instance:get_table_dizhu()
        local max_bet_times = math_floor(self.player_info.coins / (banker_info.banker_times * 3 * dizhu))
        local bet_times = get_bet_times(self)
        if bet_times > max_bet_times then
            local sorted_can_bet_times_list = instance.sorted_can_bet_times_list

            for i=#sorted_can_bet_times_list,1,-1 do
                if sorted_can_bet_times_list[i] <= max_bet_times then
                    bet_times = sorted_can_bet_times_list[i]
                    break
                end
            end
        end

        skynet.send(self.addr, "lua", "REQ_BET", self.uid, { bet_times = bet_times }, self.fd)
    elseif self.time_to_cacl_cattle then
        -- local left_time = self.calc_cattle_left_time - 2
        -- local sleep_time = 0
        -- if left_time > 0 then
        --     sleep_time = math_random(1, left_time) * 100
        --     skynet.sleep(sleep_time)
        -- end

        -- dbglog(string_format("sleep_time(%d)", sleep_time))

        self.time_to_cacl_cattle = false
        skynet.send(self.addr, "lua", "REQ_CACL_CATTLE", self.uid, {}, self.fd)
    end
end

function Methods:update_play(curr_time)
    local instance = self.instance
    if not instance then
        return false
    end

    if self.on_exiting then --正在退出
        return
    end
    self:kpqz_operate_logic()

end

-- function Methods:on_leave(uid)
--     self.leave = true
-- end

function Methods:update()
    while not self.exit do
        local curr_time = util.get_now_time()
        self:judge_use_pic(curr_time)
        
        if self.instance then
            self:update_play(curr_time)
        -- elseif self.leave then
        --     skynet.send(self.addr,"lua","REQ_LEAVE",self.uid,{},self.fd)
        --     self.on_exiting = true
        end

        skynet.sleep(50)
    end

    dbglog(self.uid, "exit")
end

function Methods:on_exit()
    self.exit = true
    R().robotmgr(1):send('.msg_handler','put_back_robots',{{type=self.player_info.type,uid=self.uid,coins=self.player_info.coins}})
end


return M
